/************************************************
* @file    	main.c
* @author 	dralee
* @version	v1.0
* @date		2021-12-03
* @brief	DMA-存储器到存储器，内部FLASH到内部SRAM
*		当使用存储器到存储器模式时，通道可以随便选，
*		没有硬性规定
*************************************************/
#include "stm32f10x.h"
#include "led.h"
#include "systick.h"

#define DMA_CHANNEL				DMA1_Channel6				// 通道6
#define DMA_CLOCK					RCC_AHBPeriph_DMA1	// DMA1
#define DMA_FLAG_TC				DMA1_FLAG_TC6				// 传输完成标志
#define BUFFER_SIZE				32									// 发送数据大小

// 使用const关键字定义常量数组常量类型，表示数据存储
// 到内存FLASH中
const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] = {
	0x01234567,0x02345678,0x03456789,0x04567891,
	0x11234567,0x12345678,0x13456789,0x14567891,
	0x21234567,0x22345678,0x23456789,0x24567891,
	0x31234567,0x32345678,0x33456789,0x34567891,
	0x41234567,0x42345678,0x43456789,0x44567891,
	0x51234567,0x52345678,0x53456789,0x54567891,
	0x61234567,0x62345678,0x63456789,0x64567891,
	0x71234567,0x72345678,0x73456789,0x74567891
};

// 定义DMA传输目标存储器
// 存储在内部SRAM
uint32_t aDst_Buffer[BUFFER_SIZE];

uint8_t BufferCmp(const uint32_t *pBufferSrc, uint32_t *pBufferDst, uint16_t bufferLength);
void DMA_Config(void);

/**
 *****************************************
 * @brief 主函数
 * @param 无
 * @retval 无
 *****************************************/
int main(void)
{
	uint8_t transferStatus;
	
	LED_GPIO_Config();
	LED_PURPLE;					// 默认显示紫色
	Delay_ms(1000);			// 延时1s
	
	DMA_Config();				// DMA传输配置
	
	while(DMA_GetFlagStatus(DMA_FLAG_TC) == RESET); // 等待DMA传输完成
	
	transferStatus = BufferCmp(aSRC_Const_Buffer, aDst_Buffer, BUFFER_SIZE); // 比较传输结果
	
	if(transferStatus == 0) // 不一致，红灯
	{
		LED_RED;
	}
	else // 一致，蓝灯
	{
		LED_BLUE;
	}
	
	while(1)
	{
		
	}
}

/**
 *****************************************
 * @brief 配置DMA
 * @param 无
 * @retval 无
 *****************************************/
void DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStruct;
	
	RCC_AHBPeriphClockCmd(DMA_CLOCK, ENABLE); // 开启DMA时钟
	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer; 	// 源数据地址
	DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)aDst_Buffer;						// 目标地址
	DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; 											// 方向：外设到存储器（外设是内部FLASH）
	DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE;													// 传输大小
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable;					// 外设（内部FLASH）地址递增
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;									// 内存地址递增
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;	// 外设数据单位
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;					// 内存数据单位
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;														// DMA模式，一次或循环模式
	DMA_InitStruct.DMA_Priority = DMA_Priority_High;											// 优先级高
	DMA_InitStruct.DMA_M2M = DMA_M2M_Enable;															// 使能内存到内存传输
	DMA_Init(DMA_CHANNEL, &DMA_InitStruct);																// 配置DMA通道
	
	DMA_ClearFlag(DMA_FLAG_TC);																						// 清除DMA数据传输完成标志位
	DMA_Cmd(DMA_CHANNEL, ENABLE);																					// DMA使能
	
}

/**
 *****************************************
 * @brief 判断指定长度两个数据源是否完全相等
 * @param pBufferSrc 原数据
 * @param pBufferDst 目标数据
 * @param bufferLength 数据长度
* @retval 相等返回1，其中一对数据不相等返回0
 *****************************************/
uint8_t BufferCmp(const uint32_t *pBufferSrc, uint32_t *pBufferDst, uint16_t bufferLength)
{
	while(bufferLength--)
	{
		if(*pBufferSrc != *pBufferDst) // 是否相等
		{
			return 0;
		}
		// 地址指针递增
		pBufferSrc++;
		pBufferDst++;
	}
	return 1; // 完全相等
}
